package krillr.Predictors;
import robocode.*;
import robocode.util.Utils;
import krillr.Util.*;
import java.util.*;

public class GuessFactorC extends Predictor {
    ArrayList waves = new ArrayList();
    private int uniqueSegments = 31;
    private int fieldSegments = 5;
    private int distanceSegments = 6;
    private int velocitySegments = 5;
    private int xForceSegments = 7;
    private int yForceSegments = 7;
    private int[][][][][] stats = new int[fieldSegments][distanceSegments][velocitySegments][yForceSegments][uniqueSegments];
    //private int headingSegments = 20;
    //private int[][][][][] stats = new int[fieldSegments][distanceSegments][velocitySegments][headingSegments][uniqueSegments];
    private int[] currentStats;
    private int direction = 1;
    
    private double maxDistance;
    
    public GuessFactorC(KrillBot b, Tracker u) {
        bot = b;
        unit = u;
        maxDistance = new Point2d(0,0).distance(bot.getBattleFieldWidth(), bot.getBattleFieldHeight());
    }
    
    public void run() {
        Point2d enemyPos = unit.lastKnownLocation();
        
        //let's process the waves now:
        for (int i=0; i<waves.size(); i++)
        {
            WaveBullet currentWave = (WaveBullet)waves.get(i);
            if (currentWave.check(enemyPos, bot.getTime()))
            {
                waves.remove(currentWave);
                i--;
            }
        }
        return;
    }
    
    public void update() {
        double absBearing = unit.lastKnownAbsoluteBearing();
        //find our enemy's location:
        Point2d enemyPos = unit.lastKnownLocation();
        
        double power = 3;
        double orientation = KrillUtil.sign(unit.velocity()*Math.sin(unit.heading() - unit.lastKnownAbsoluteBearing()));
        bot.out.print("Orientation: "+orientation);
        int distanceIndex = (int)unit.lastKnownDistance()/((int)maxDistance/distanceSegments);
        int velocityIndex = (int)unit.velocity()/2;
        int xForceIndex = (int)((unit.vector().Normalise().getX()+1));
        int yForceIndex = (int)((unit.vector().Normalise().getY()+1));
        int fieldIndex = getOutIndex();
        bot.out.println("Distance Index: "+distanceIndex);
        bot.out.println("Velocity Index: "+velocityIndex);
        bot.out.println("XForce Index  : "+xForceIndex);
        bot.out.println("YForce Index  : "+yForceIndex);
        //bot.out.println(headingIndex);
        bot.out.println("Field Index: "+fieldIndex);
        currentStats = stats[fieldIndex][distanceIndex][velocityIndex][yForceIndex];
        //currentStats = stats[fieldIndex][distanceIndex][velocityIndex][headingIndex];
        WaveBullet newWave = new WaveBullet(new Point2d(bot.getX(), bot.getY()), new Vector2d(absBearing, KrillUtil.getBulletSpeed(power)), orientation, bot.getTime(), currentStats);
        waves.add(newWave);
    }
    
    public Vector2d getVector() {
        Vector2d newVector = new Vector2d();
        int bestindex = 15; //initialize it to be in the middle, guessfactor 0.
        for (int i=0; i<uniqueSegments; i++)
            if (currentStats[bestindex] < currentStats[i])
            bestindex = i;
        
        //this should do the opposite of the math in the WaveBullet:
        WaveBullet w = getNewestWave();
        double guessfactor = (double)(bestindex-(stats.length-1)/2)/((stats.length-1)/2);
        double angleOffset = direction*guessfactor*w.vector.getMagnitude();
        double angle = robocode.util.Utils.normalRelativeAngle(unit.lastKnownAbsoluteBearing()+angleOffset);
        newVector.setDirection(angle);
        return newVector;
    }
    
    public WaveBullet getNewestWave() { return (WaveBullet)waves.get(waves.size()-1); }
    
    public void getSaveData() { return; }
    
    private int getOutIndex() {
        int i = 0;
        do {
            
        } while (++i < fieldSegments-1 && unit.fieldRectangle.contains((unit.lastKnownLocation().getX() + (Math.sin(unit.heading())* (45.0 * i))), (unit.lastKnownLocation().getY() + (Math.cos(unit.heading())) * (45.0 * i))));
        return (i);
    }    
}

class WaveBullet
    {
        public Point2d startPosition;
        public Vector2d vector;
        private long fireTime;
        private double orientation;
        private int[] returnSegment;
        
        public WaveBullet(Point2d position, Vector2d v, double o, long time, int[] segment)
        {
            startPosition = position;
            vector = v;
            orientation = o;
            fireTime = time;
            returnSegment = segment;
        }

        public boolean check(Point2d enemyPosition, long currentTime)
        {
            //if the distance from the wave origin to our enemy has passed the distance the bullet would have traveled...
            if (startPosition.distance(enemyPosition) <= (currentTime-fireTime)*KrillUtil.getBulletSpeed(vector.getMagnitude()))
            {
                double newBearing = KrillUtil.getBearing(startPosition, enemyPosition);
                double angleOffset = Utils.normalRelativeAngle(newBearing-vector.getDirection());
                double guessFactor = Math.max(-1, Math.min(1, angleOffset/Math.asin(8/KrillUtil.getBulletSpeed(vector.getMagnitude()))))*orientation;
                int index = (int)Math.round((returnSegment.length-1)/2*(guessFactor+1));
                returnSegment[index]++;
                return true;
            }
            return false;
        }
    }